//
//  Scene.cpp
//  RayTracer
//
//  Created by 俞云康 on 2/15/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#include "Scene.hpp"
#include "Params.hpp"
#include "Material.hpp"
#include "TriangleMesh.hpp"

shared_ptr<Scene> Scene::create(const Params& params) {
    auto s = make_shared<Scene>();
    auto& scene_params = params;
    vector<string> names;
    vector<Params> ps;
    scene_params.children(names, ps);
    for (int i = 0; i < names.size(); ++i) {
        if (names[i] == "texture") {
            Texture::create(ps[i]);
        } else if (names[i] == "material") {
            Material::create(ps[i]);
        } else if (names[i] == "shape") {
            if (ps[i].getType() == "obj") {
                auto mesh = TriangleMesh::create(ps[i]);
                s->meshes.push_back(mesh);
                auto material = Material::create(ps[i].child("material"));
				if (ps[i].hasTypedChild("areaLight")) {
					auto area_light = AreaLight::create(ps[i].child("areaLight"));
					for (auto& t : mesh->triangles) {
						auto al = area_light->clone();
						auto gp = make_shared<GeometricPrimitive>(t, material, al);
						al->geometricPrimitive = gp;
						s->add(al);
						//s->add(gp);
					}
				}
				else {
					for (auto& t : mesh->triangles) {
						s->add(make_shared<GeometricPrimitive>(t, material, nullptr));
					}
				}
            } else {
				auto gp = GeometricPrimitive::create(ps[i]);
                s->add(gp);
				if (gp->isEmitter()) {
					s->add(gp->getAreaLightShared());
				}
            }
        }
		//else if (names[i] == "areaLight") {
  //          s->add(AreaLight::create(ps[i]));
  //      }
		else {
            warning("unknown node type: %s\n", names[i].c_str());
        }
    }
    s->mKDtree = make_shared<KDTree>(s->geometricPrimitives);
    return s;
}


//void Scene::add(const std::shared_ptr<Shape> shape) {
//    shapes.push_back(shape);
//    boundingBox.expandBy(shape->boundingBox);
//}

void Scene::add(const std::shared_ptr<GeometricPrimitive> geometricPrimitive) {
    geometricPrimitives.push_back(geometricPrimitive);
}


void Scene::add(const std::shared_ptr<Light> light) {
    lights.push_back(light);
}


void Scene::add(const std::shared_ptr<AreaLight> light) {
	Assert(light != nullptr && light->geometricPrimitive != nullptr);
    area_lights.push_back(light);
    geometricPrimitives.push_back(light->geometricPrimitive);
}